package com.example.communist_app_api.service.impl;

import com.example.communist_app_api.config.mq.NoticeTask;
import com.example.communist_app_api.db.dao.*;
import com.example.communist_app_api.db.dto.ActivityDTO;
import com.example.communist_app_api.db.dto.ActivityUniAppShowDTO;
import com.example.communist_app_api.db.dto.UserActivityDTO;
import com.example.communist_app_api.db.dto.UserDTO;
<<<<<<< HEAD
import com.example.communist_app_api.db.pojo.Activity;
import com.example.communist_app_api.db.pojo.Organization;
import com.example.communist_app_api.db.pojo.User;
import com.example.communist_app_api.db.pojo.UserActivity;
<<<<<<< HEAD
import com.example.communist_app_api.enums.SenderNameEnum;
=======
import com.example.communist_app_api.db.pojoDto.Activity;
import com.example.communist_app_api.db.pojoDto.Organization;
import com.example.communist_app_api.db.pojoDto.User;
import com.example.communist_app_api.db.pojoDto.UserActivity;
>>>>>>> 党建uniapp/dev
=======
>>>>>>> parent of aec1d46 (消息模块的搭建和配合其他模块消息的发送和收取)
import com.example.communist_app_api.exception.GlobalException;
import com.example.communist_app_api.service.ActivityService;
import com.example.communist_app_api.service.UserActivityService;

import com.example.communist_app_api.util.RedisUtil;
import com.example.communist_app_api.vo.uniapp.req.UniAppShowActivityByConditionReq;
import com.example.communist_app_api.vo.uniapp.resp.UniAppMyActivityDetailResp;
import com.example.communist_app_api.vo.web.req.ActivityCreateReq;
import com.example.communist_app_api.vo.web.req.ActivityUpdateReq;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author Brother Sheng Editor
 * @version 1.0
 * Create by 2023/2/26 15:27
 */
@Transactional
@Service
public class ActivityServiceImpl implements ActivityService {

    @Autowired
    private ActivityDao activityDao;

    @Autowired
    private UserActivityService userActivityService;

    @Autowired
    private UserActivityDao userActivityDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private UserOrganizationDao userOrganizationDao;

    @Resource
    RedisUtil redisUtil;

    @Autowired
    private NoticeTask noticeTask;

    @Autowired
    private OrganizationDao organizationDao;


    @Override
    public Boolean createActivity(ActivityCreateReq req, Integer userId) {
        //图片地址
        List<String> photoUrlList = req.getPhotoUrlList();
        String photoUrl = "";
        if (photoUrlList != null && photoUrlList.size() != 0) {
            photoUrl = String.join(",", req.getPhotoUrlList());
        }
        Activity activity = new Activity();
        activity.setTitle(req.getTitle());
        activity.setContext(req.getContext());
        activity.setStyle(req.getStyle());
        List<Date> dateRange = req.getDateRange();
        if (dateRange.size() != 2) {
            throw new RuntimeException("时间段有误");
        }
        Date startTime = dateRange.get(0);
        Date endTime = dateRange.get(1);

        if (startTime.compareTo(endTime) >= 0) {
            throw new GlobalException("时间段设置不合法");
        }

        activity.setPlace(req.getPlace());
        activity.setActivityRequirement(req.getActivityRequirement());
        activity.setStartTime(startTime);
        activity.setEndTime(endTime);
        activity.setLimitedNum(req.getLimitedNum());
        activity.setPhotoUrl(photoUrl);
        activity.setUserId(userId);
        Integer status = activityDao.insert(activity);
        return status == 1;

    }

    @Override
    public PageInfo<ActivityDTO> selectByCommon(Activity activity, Integer pageNum, Integer pageSize, Integer userId) {
        Page<ActivityDTO> page = new Page<>(pageNum, pageSize);
        //查询与userId相同组织的发布的活动
        //判断userId的组织是党总支还是党支部
        Organization organization = userOrganizationDao.getOrganizationByUserId(userId);
        Integer organizationId = organization.getId();
        //parentId作为userId组织的父组织中的parentId
        Integer parentId = organizationDao.getOrganizationByOrganizationId(organization.getParentId()).getParentId();

        List<ActivityDTO> activityDTOList = new ArrayList<>();
        List<Integer> activityIdList = new ArrayList<>();
        List<Integer> organizationIdList = new ArrayList<>();
        organizationIdList.add(organizationId);
        if (parentId != 0){
            //判断说明是本党支部，只能查看本党支部的活动
            //查
            activityDTOList = activityDao.selectByCommon(activity, organizationIdList);

        }else{
            //党总支能看到，本党总支和总支下面所有党支部的活动
            organizationIdList.addAll(organizationDao.getOrganizationIdListByParentId(organizationId));
            activityDTOList = activityDao.selectByCommon(activity, organizationIdList);
        }
        //拿
        activityIdList = activityDTOList.stream()
                .map(ActivityDTO::getId)
                .collect(Collectors.toList());
        //组
        HashMap<Integer, Integer> activityHashMap = userActivityService.getApplicationNumberByActivityIdList(activityIdList);
        //塞
        Date date = new Date();
        activityDTOList.forEach(activityDTO -> {
            activityDTO.setApplicationNum(activityHashMap.get(activityDTO.getId()));
            activityDTO.setAllowedSign(date.compareTo(activityDTO.getEndTime()) < 0 && date.compareTo(activityDTO.getStartTime()) > 0);
            if (date.compareTo(activityDTO.getStartTime())>0) {
                activityDTO.setSentenceUpdateFlag(false);
            }else {
                activityDTO.setSentenceUpdateFlag(true);
            }
        });

        page.setTotal(activityIdList.size());
        activityDTOList = activityDTOList.stream().skip((long) (pageNum - 1) * pageSize)
                .limit(pageSize).collect(Collectors.toList());
        page.addAll(activityDTOList);
        return new PageInfo<>(page);
    }

    @Override
    public Boolean updateActivity(ActivityUpdateReq req) {
        //图片地址
        List<String> photoUrlList = req.getPhotoUrlList();
        String photoUrl = "";
        if (photoUrlList != null && photoUrlList.size() != 0) {
            photoUrl = String.join(",", req.getPhotoUrlList());
        }
        Activity activity = new Activity();
        activity.setTitle(req.getTitle());
        activity.setContext(req.getContext());
        activity.setStyle(req.getStyle());
        //未被修改的activity
        //对更新时间进行严格要求，理论上更新开始时间和结束时间都不能早于活动创建时间；
        ActivityDTO initActivityDTO = activityDao.selectActivityById(req.getId());
        List<Date> dateRange = req.getDateRange();
        if (dateRange.size() != 2) {
            throw new RuntimeException("时间段有误");
        }
        Date startTime = dateRange.get(0);
        Date endTime = dateRange.get(1);

        if (startTime.compareTo(endTime) > 0) {
            throw new GlobalException("活动设置开始时间晚于结束时间，请重新设置");
        }

        if (startTime.compareTo(endTime) == 0) {
            throw new GlobalException("活动设置开始时间等于结束时间，请重新设置");
        }

        if (initActivityDTO.getCreatedTime().compareTo(startTime) > 0) {
            throw new GlobalException("活动更新设置开始时间早于活动创建时间，请重新设置");
        }

        if (initActivityDTO.getCreatedTime().compareTo(endTime) > 0) {
            throw new GlobalException("活动更新设置结束时间早于活动创建时间，请重新设置");
        }

        activity.setPlace(req.getPlace());
        activity.setActivityRequirement(req.getActivityRequirement());
        activity.setStartTime(startTime);
        activity.setEndTime(endTime);
        activity.setLimitedNum(req.getLimitedNum());
        activity.setPhotoUrl(photoUrl);
        if (req.getId() == null) {
            throw new GlobalException("缺乏活动ID,请重新传输");
        }
        activity.setId(req.getId());
        Integer status = activityDao.updateActivity(activity);
        //更新活动成功之后发送系统消息给已经报名参加的人，告知活动更新了
        String title = activity.getTitle();
        String message = "您报名参加“"+title+"”的活动信息有更新，请到个人活动中心查看！感谢您的参与！";
        List<Integer> userIdListByActivityId = userActivityService.getUserIdListByActivityId(req.getId());
        String senderName = "活动通知";
        noticeTask.sendSystemNoticeBatch(userIdListByActivityId,message,senderName);
        return status == 1;
    }

    @Override
    public Integer deleteActivity(Integer id) {
        //同时也要处理user_activity表相关数据
        userActivityDao.updateDeleteUserActivity(id);
        return activityDao.deleteActivity(id);
    }

    //web端方法查看活动详情方法
    @Override
    public ActivityDTO selectActivityById(Integer id) {

        ActivityDTO activityDTO = activityDao.selectActivityById(id);
        activityDTO.setDateRange(Arrays.asList(activityDTO.getStartTime(), activityDTO.getEndTime()));
        //查询活动参与人数
        ArrayList<Integer> activityIdList = new ArrayList<>();
        activityIdList.add(id);
        Integer applicationNumber = userActivityService.getApplicationNumberByActivityIdList(activityIdList).get(id);
        activityDTO.setApplicationNum(applicationNumber);
        List<Integer> userIdList = userActivityService.getUserIdListByActivityId(id);
        //防止查询到空的list，导致报错
        if (userIdList != null && userIdList.size() != 0) {
            List<UserDTO> userDTOList = userDao.getUserDTOListByUserIdList(userIdList);
            activityDTO.setUserDTOList(userDTOList);
        }
        return activityDTO;
    }

    @Override
    public List<ActivityUniAppShowDTO> uniAppShowActivityByCondition(UniAppShowActivityByConditionReq req, int userId) {
        //查询全部活动，分为可报名和结束报名两种状态，可以进行搜索,显示以开始时间倒序显示
        //规定活动开始前一个小时停止报名
        //先查询自己组织发布的活动
        //根据UserId获取本支部organization信息
        Organization organization = userOrganizationDao.getOrganizationByUserId(userId);
        Integer organizationId = organization.getId();
        //查看上级总支发布的活动
        Integer parentId = organizationDao.getOrganizationByOrganizationId(organization.getParentId()).getParentId();

        //判断是否进行选择(可报名或结束报名两种状态)
        //把当前时间放入afterOneHourToNowDate中，获取一个小时之后的时间
        Date date = afterOneHourToNowDate(new Date(System.currentTimeMillis()));
        List<ActivityUniAppShowDTO> activityListByAdmit = new ArrayList<>();
        List<ActivityUniAppShowDTO> activityListByForbid;

        //组装list<Integer> organizationList
        List<Integer> organizationIdList = new ArrayList<>();
        //添加本组织
        organizationIdList.add(organizationId);
        //判断上级是否是总支还是党委
        if (parentId !=0){
            //如果parentId不为0说明这个是该用户的组织是属于党支部
            //本组织+党总支发布的活动
            //根据organizationId来选择，即筛选本组织的活动
            organizationIdList.add(parentId);
        }else {
            //该用户是党总支的成员
            //获取党总支+下面所属所有党支部的活动
            organizationIdList =organizationDao.getOrganizationIdListByParentId(organizationId);
        }

        if (req.getStatus().equals("可报名")) {
            //只选择可报名的活动
            //可报名
            activityListByAdmit = activityDao.selectActivityByUniAppAndAdmit(req.getTitle(), date, organizationIdList);
            activityListByAdmit.stream().forEach(n -> {
                n.setStatus("可报名");
            });
        } else if (req.getStatus().equals("结束报名")) {
            //结束报名
            activityListByForbid = activityDao.selectActivityByUniAppAndForbid(req.getTitle(), date, organizationIdList);
            activityListByForbid.stream().forEach(n -> {
                n.setStatus("结束报名");
            });
            activityListByAdmit.addAll(activityListByForbid);
        } else {
            //不分状态
            //可报名
            activityListByAdmit = activityDao.selectActivityByUniAppAndAdmit(req.getTitle(), date, organizationIdList);
            activityListByAdmit.forEach(n -> {
                n.setStatus("可报名");
            });
            //结束报名
            activityListByForbid = activityDao.selectActivityByUniAppAndForbid(req.getTitle(), date, organizationIdList);
            activityListByForbid.forEach(n -> {
                n.setStatus("结束报名");
            });
            activityListByAdmit.addAll(activityListByForbid);
        }
        return activityListByAdmit;
    }

    @Override
    public ActivityDTO selectUniAppActivityById(Integer activityId) {
        ActivityDTO activityDTO = activityDao.selectActivityById(activityId);
        return activityDTO;
    }

    @Override
    public String generateSignCode(Integer activityId) {
        ActivityDTO activityDTO = activityDao.selectActivityById(activityId);
        Optional.ofNullable(activityDTO).orElseThrow(() -> new GlobalException("找不到该活动"));
        Date date = new Date();
        if (date.compareTo(activityDTO.getEndTime()) > 0) {
            throw new GlobalException("活动已结束");
        }
        if (date.compareTo(activityDTO.getStartTime()) < 0) {
            throw new GlobalException("活动还没开始");
        }
        UUID uuid = UUID.randomUUID();
        redisUtil.set(String.valueOf(activityId), uuid.toString(), 60);
        return uuid.toString();
    }

    @Override
    public void sign(Integer activityId, String code, Integer userId) {
        ActivityDTO activityDTO = activityDao.selectActivityById(activityId);

        Date date = new Date();
        if (date.compareTo(activityDTO.getEndTime()) > 0) {
            throw new GlobalException("签到失败，活动已结束");
        }

        String correctCode = (String) redisUtil.get(String.valueOf(activityId));
        Optional.ofNullable(correctCode)
                .orElseThrow(() -> new GlobalException("验证码已失效"));

        if (!correctCode.equals(code)) {
            throw new GlobalException("验证码已失效");
        }

        UserActivity userActivity = userActivityDao.getUserActivityByActivityIdAndUserId(activityId, userId);

        Optional.ofNullable(userActivity)
                .orElseThrow(() -> new GlobalException("签到失败，未参加该活动"));
        //修改时添加签到时间
        int update = userActivityDao.updateUserActivityByActivityIdAndUserId(activityId, userId,date);

        if (update == 0) {
            throw new GlobalException("重复签到");
        }

    }

    @Override
    public  Map<Boolean, List<UserActivityDTO>> getSignUserList(Integer activityId) {
        List<UserActivity> list = userActivityDao.getUserActivityListByActivityId(activityId);
        if(list.size()==0){
            return new HashMap<>();
        }

        List<Integer> userIdList = list
                .stream()
                .map(UserActivity::getUserId)
                .collect(Collectors.toList());

        List<User> userList = userDao.getUserListByIds(userIdList);

        Map<Integer, User> userMap = userList
                .stream()
                .collect(Collectors.toMap(User::getId, user -> user));

        List<UserActivityDTO> activityDTOList = list
                .stream()
                .map(userActivity -> {
                    Integer userId = userActivity.getUserId();
                    User user = userMap.get(userId);
                    UserActivityDTO userActivityDTO = new UserActivityDTO();
                    userActivityDTO.setUserName(user.getName());
                    userActivityDTO.setPhoto(user.getPhoto());
                    userActivityDTO.setSignIn(userActivity.getSignIn());
                    userActivityDTO.setUserId(userId);
                    userActivityDTO.setSignTime(userActivity.getUpdatedTime());
                    userActivityDTO.setActivityId(userActivity.getActivityId());
                    userActivityDTO.setId(userActivity.getId());
                    return userActivityDTO;
                }).collect(Collectors.toList());

        return activityDTOList
                .stream()
                .collect(Collectors.groupingBy(userActivityDTO -> userActivityDTO.getSignIn() != 0));
    }

    @Override
    public void additionalSign(Integer userId, String organizersId, Integer activityId) {
        ActivityDTO activityDTO = activityDao.selectActivityById(activityId);
        Optional.ofNullable(activityDTO)
                .orElseThrow(()->new GlobalException("没有这个活动"));

        User user = userDao.getUserByUserId(Integer.parseInt(activityDTO.getUserId()));
        Optional.ofNullable(user)
                .orElseThrow(()->new GlobalException("用户不存在"));

        if(!String.valueOf(organizersId).equals(user.getName())){
            throw new GlobalException("无权限");
        }
        //修改时新增签到时间
        Date date = new Date();
        int update = userActivityDao.updateUserActivityByActivityIdAndUserId(activityId, userId,date);

        if(update==0){
            throw new GlobalException("补签失败");
        }
    }

    @Override
    public UniAppMyActivityDetailResp getMyActivityDetailByActivityIdAndUserId(Integer activityId, int userId) {
        UniAppMyActivityDetailResp resp = new UniAppMyActivityDetailResp();
        //根据activityId查询活动详情
        ActivityDTO activityDTO = activityDao.selectActivityById(activityId);
        resp.setTitle(activityDTO.getTitle());
        resp.setStyle(activityDTO.getStyle());
        resp.setPlace(activityDTO.getPlace());
        resp.setCreateTime(activityDTO.getCreatedTime());
        DateTime signTime = userActivityDao.getSignTimeByUserIdAndActivityId(userId,activityId);
        resp.setSignTime(signTime);
        resp.setStartTime(activityDTO.getStartTime());
        resp.setEndTime(activityDTO.getEndTime());
        resp.setContext(activityDTO.getContext());
        resp.setActivityRequirement(activityDTO.getActivityRequirement());
        return resp;
    }

    public static Date afterOneHourToNowDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        /* HOUR_OF_DAY 指示一天中的小时 */
        calendar.setTime(date);
        calendar.add(Calendar.HOUR_OF_DAY, 1);
        return calendar.getTime();
    }

}
